package main.labtwo;

import static java.lang.Math.abs;

/**
 * Created with IntelliJ IDEA.
 * User: Борис
 * Date: 23.11.13
 * Time: 15:43
 * To change this template use File | Settings | File Templates.
 */
public class MethodsGauss {
    private int vector[];  // вектор перестановок
    private double matrixOfSystemEx[][];   // расширенная матрица системы
    private double copyMatrixOfSystem[][];
    private double[] B; // столбец свободных членов
    private double[] B1; // проверка
    private double[][] matrixOfSystem; // матрица системы
    private double[] X;
    private int strings;   // число строк матрицы copyMatrixOfSystem[][]

    public MethodsGauss(double matrixOfSystemEx[][]){
        this.matrixOfSystemEx = matrixOfSystemEx;
        this.copyMatrixOfSystem = copyMatrix(matrixOfSystemEx);
        int sizeVector;
        strings = sizeVector = matrixOfSystemEx.length;
        vector = new int[sizeVector];
        for(int i = 0; i<sizeVector; i++)
            vector[i] = i+1;
        matrixOfSystem = new double[strings][strings];
        for(int i = 0; i<strings; i++)
            for(int j = 0; j<strings; j++){
                matrixOfSystem[i][j] = matrixOfSystemEx[i][j];
            }
        B = new double[strings];
        for(int i = 0; i<strings; i++)
            B[i] = matrixOfSystemEx[i][strings];
        B1 = new double[B.length];
        X = new double[strings];
    }

    double[] getX(){
        return X;
    }

    //создат копию расширинной матрицы системы и возвращает ссылку на неё
    private double[][] copyMatrix(double matrixOfSystem[][]){
        int strings = matrixOfSystem.length;   // число строк
        int columns = strings+1;
        double copyMatrix[][] = new double[strings][columns];
        for(int i = 0; i<strings; i++)
            for(int j = 0; j<columns; j++){ // число столбцов на единицу больше, чем число строк
                copyMatrix[i][j] = matrixOfSystem[i][j];
            }
        return copyMatrix;
    }

    // меняет первый столбец и столбец с индексом index местами
    private void swapColumn(int index0, int index1){
        double swap;
        for(int i = 0; i<strings; i++){
            swap = this.copyMatrixOfSystem[i][index0];
            this.copyMatrixOfSystem[i][index0] = this.copyMatrixOfSystem[i][index1];
            this.copyMatrixOfSystem[i][index1] = swap;
        }
        // изменяю вектор перестановок
        int numCol;
        numCol = vector[index0];
        vector[index0] = vector[index1];
        vector[index1] = numCol;
    }
    // меняет первую строку и строку с индексом index местами
    private void swapString(int index0,int index1){
        int columns = copyMatrixOfSystem.length+1; // число столбцов
        double swap;
        for(int i = 0; i<columns; i++){
            swap = copyMatrixOfSystem[index0][i];
            copyMatrixOfSystem[index0][i] = copyMatrixOfSystem[index1][i];
            copyMatrixOfSystem[index1][i] = swap;
        }
    }
    // ищет главный элемент в матрице и перестанавливает его на первое место
    private void mainElementOfMatrix(int index){
        int iMax = index, jMax = index;
        int strings = copyMatrixOfSystem.length;             // число строк
        double max = abs(copyMatrixOfSystem[index][index]);
        for(int i = index; i<strings; i++)
            for(int j = index; j<strings; j++){
                if (abs(copyMatrixOfSystem[i][j])>max){
                    max = abs(copyMatrixOfSystem[i][j]);
                    iMax = i;
                    jMax = j;
                }
            }
       // System.out.printf("\n%s %.2f %s \n","главный элемент",copyMatrixOfSystem[iMax][jMax]," i = "+(iMax+1)+" j = "+(jMax+1));
        if (iMax!=index) swapString(iMax,index);
        if (jMax!=index) swapColumn(jMax,index);
    }
    // складывает две строки
    private void sumLine(double string1[], double string2[]){
        for(int i = 0; i<string1.length; i++){
            string2[i] += string1[i];
        }
    }
    //умножает каждый элемент line на -a
    private double[] multiply(double line[],double a){
        int size = line.length;
        if (a!=0) a = -a;
        double result[] = new double[size];
        for(int i = 0; i<size; i++)
            result[i] = line[i] * a;
        return result;
    }
    // возвращает копию строки line
    private double[] copyLine(double[] line){
        int size = line.length;
        double[] copyLine = new double[size];
        for(int i = 0; i<size; i++){
            copyLine[i] = line[i];
        }
        return copyLine;
    }
    // разделяет первую строку на первый элемент и обращает в нуль все элементы, находящиеся под первым
    private void stageDown(int index){
        int size = copyMatrixOfSystem[0].length; // длина строки
        double mainElement = copyMatrixOfSystem[index][index];
        double[] line1;
        for(int i = 0; i<size; i++)
            copyMatrixOfSystem[index][i] /= mainElement;
        //showMatrixAndVector();
        line1 = copyLine(copyMatrixOfSystem[index]);
        for(int i = index; i<size-2; i++){
            sumLine(multiply(line1,copyMatrixOfSystem[i+1][index]),copyMatrixOfSystem[i+1]);
            //showMatrixAndVector();
        }
    }
    // прямой ход
    private void down(){
        int it = this.copyMatrixOfSystem.length;
        for(int i = 0; i<it; i++){
            mainElementOfMatrix(i);
            //showMatrixAndVector();
            stageDown(i);
        }
    }

    private void stageUp(int index){
        double[] line1 = copyLine(copyMatrixOfSystem[index]);
        for(int i = index; i>0; i--){
            sumLine(multiply(line1,copyMatrixOfSystem[i-1][index]),copyMatrixOfSystem[i-1]);
            //showMatrixAndVector();
        }
    }
    // обратный ход
    private void up(){
        int size = copyMatrixOfSystem.length;
        for(int i = size-1; i>0; i--){
            stageUp(i);
        }
    }
    // вычисление неизвестных системы уравнений методом Гаусса
    void findX(){
        down();
        up();
        for(int i = 0; i<strings; i++){
            X[vector[i]-1] = copyMatrixOfSystem[i][strings];
        }
    }
}
